package com.xtpt.disaster.controller;

import com.alibaba.fastjson.JSON;
import com.xtpt.disaster.bean.*;
import com.xtpt.disaster.common.ORACLE.OracleCmdBuilder;
import com.xtpt.disaster.common.PortalResult;
import com.xtpt.disaster.common.consts.DataTypeEnum;
import com.xtpt.disaster.common.consts.BackupTypeEnum;
import com.xtpt.disaster.common.consts.StatusConst;
import com.xtpt.disaster.common.consts.TaskTypeEnum;
import com.xtpt.disaster.service.DBMysqlJobDetailService;
import com.xtpt.disaster.service.DBNodeInfoService;
import com.xtpt.disaster.service.JobDetailService;
import com.xtpt.disaster.service.TaskInfoManageService;
import com.xtpt.disaster.utils.*;
import io.swagger.annotations.Api;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@CrossOrigin
//@ComponentScan("com.example.spring")
@RestController
@RequestMapping("/oracle/")
@Api(tags = "Oracle数据库备份删除")
public class DBOracleController{

    @Autowired
    JobDetailService jobDetailService;

    @Autowired
    DBNodeInfoService dbNodeInfoService;

    @Autowired
    OracleCmdBuilder oracleCmdBuilder;

    @Autowired
    QuartzSendBack quartzSendBack;

    @Autowired
    TaskInfoManageService taskInfoManageService;

    @Autowired
    DBMysqlJobDetailService dbMysqlJobDetailService;

    @Autowired
    ServerPathUtil serverPathUtil;


    @PostMapping("/submit")
    public PortalResult submit(@RequestBody TaskInfo parameters) {
        ParametersTask quartzInfo=new ParametersTask();
        // 将参数传递到调度任务所需实体
        BeanUtils.copyProperties(parameters, quartzInfo);
        Long taskId = IDGenerator.longid();
        // 插入数据库
        parameters.setTaskId(taskId);
        // 生成任务id
        quartzInfo.setTaskId(taskId);
        // 判断任务类型
        TaskTypeEnum taskType=TaskTypeEnum.getObject(parameters.getTaskType());
        String callbackUrl;
        boolean statusOK=false;
        if(taskType==TaskTypeEnum.BACKUP)
        {
            ParametersDBBackup backup = new ParametersDBBackup();
            backup.setTaskId(taskId);
            BeanUtils.copyProperties(parameters, backup);
            callbackUrl=serverPathUtil.generateCallbackUrl("/oracle/backup");
            statusOK= quartzSendBack.taskRegister(quartzInfo,callbackUrl,backup);
        }
        else if (taskType==TaskTypeEnum.RECOVER)
        {
            ParametersDBRecover recover=new ParametersDBRecover();
            BeanUtils.copyProperties(parameters, recover);
            callbackUrl=serverPathUtil.generateCallbackUrl("/oracle/recover");
            statusOK= quartzSendBack.taskRegister(quartzInfo,callbackUrl,recover);
        }
        else
        {
            return PortalResult.error("需选择 备份 或 恢复 中的一个！");
        }
        if(statusOK) {
            int count = taskInfoManageService.insertOneTaskInfo(parameters);
            if (count == 1) {
                return PortalResult.ok();
            } else {
                return PortalResult.error("新建任务失败");
            }
        } else {
            return PortalResult.error("创建计划任务失败！");
        }
    }
    @RequestMapping("/backup")
    public PortalResult backup(@RequestBody ParametersDBBackup backupInfo)
    {
        DbnodeInfo dbNodeInfo=dbNodeInfoService.selectByPrimaryKey(backupInfo.getDbId());
        JobDetail jobDetail = JobDetailUtil.generateBackUpJobDetail(backupInfo,dbNodeInfo.getNodeDbType(),backupInfo.getDbId());
        try {
            // 备份拼接文件名
            String startTimeStr = TimeUtil.dateToString(jobDetail.getJobStartTime());
            String backupName = dbNodeInfo.getNodeDbName() + "_" + startTimeStr;
            // 设置客户端信息用于命令生成
            oracleCmdBuilder.initializeWithClientNode(dbNodeInfo);
            // 生成回调地址
            String resultReceiver = serverPathUtil.generateCallbackUrl("/oracle/receiver/"+jobDetail.getJobId());
            // 设置回调地址
            oracleCmdBuilder.setResultCallBackUrl(resultReceiver);

            BackupTypeEnum backupType = BackupTypeEnum.getObject(backupInfo.getTaskBackupType());
            // 生成备份所需命令组并返回以 备份文件在服务器的路径作为key，以备份文件在客户机的路径作为value的map
            Map<String,String> serverToClientFiles=
                    oracleCmdBuilder.dbBackUp(backupInfo.getTaskId().toString(),
                            backupName,
                            backupType.toString(),
                            backupInfo.getTaskDesc()+"("+jobDetail.getJobId()+")",
                            jobDetail.getJobId().toString()
                    );
            // 将备份命令转化为json字符串
            String cmd=oracleCmdBuilder.buildToJSONString();
            System.out.println("提交到客户端！");
            // 将命令提交到代理端执行
            String postToClient = cn.hutool.http.HttpUtil.post(dbNodeInfo.getNodeClientAgentUrl(),cmd);
            System.out.println("提交到客户端结束！");
            // 保存命令
            jobDetail.setJobCommand(cmd);
            // 设置数据类型
            jobDetail.setDataType(backupInfo.getTaskFileType());
            // 获取代理对命令的响应
            PortalResult portalResult = JSON.parseObject(postToClient,PortalResult.class);
            if(portalResult.getStatus().equals(StatusConst.SUCCESS))
            {
                StringBuilder serverFilesPath= new StringBuilder();
                StringBuilder clientFilesPath= new StringBuilder();
                for (Map.Entry<String,String> entry:serverToClientFiles.entrySet()){
                    serverFilesPath.append(entry.getKey()).append(",");
                    clientFilesPath.append(entry.getValue()).append(",");
                }
                // 保存服务端路径
                jobDetail.setServerPath(serverFilesPath.deleteCharAt(serverFilesPath.length()-1).toString());
                // 保存客户端路径
                jobDetail.setClientPath(clientFilesPath.deleteCharAt(clientFilesPath.length()-1).toString());
            }
            else
            {
                jobDetail.setJobStatus(StatusConst.ERROR);
                jobDetail.setJobResult("请求代理客户端失败："+portalResult);
            }
        } catch (Exception e) {
            jobDetail.setJobStatus(StatusConst.ERROR);
            jobDetail.setJobResult(e.getMessage());
            e.printStackTrace();
        }
        // 将job记录存入表中
        int count = dbMysqlJobDetailService.insert(jobDetail);
        if(count>0) {
            return PortalResult.ok("备份任务执行中，请稍后查看执行结果！");
        } else {
            return PortalResult.error("备份记录到作业表中时失败");
        }
    }
    @RequestMapping("/recover")
    public PortalResult recover(@RequestBody ParametersDBRecover recoverInfo)
    {
        String errorMsg="";
        JobDetail backupJobDetail = dbMysqlJobDetailService.selectByPrimaryKey(recoverInfo.getJobDetailId());
        if(backupJobDetail==null)
        {
            return PortalResult.error("jobId不存在！");
        }
        Long dbID=backupJobDetail.getDbId();
        if(dbID==null)
        {
            return PortalResult.error("dbID不存在！");
        }
        DbnodeInfo client=dbNodeInfoService.selectByPrimaryKey(dbID);
        JobDetail jobDetail = JobDetailUtil.generateRestoreJobDetail(backupJobDetail.getTaskId(),
                recoverInfo.getTaskName(),
                client.getNodeDbType(),
                dbID,
                recoverInfo.getTaskDesc());
        try {
            // 设置客户端信息用于命令生成
            oracleCmdBuilder.initializeWithClientNode(client);
            // 生成回调地址
            String resultReceiver = serverPathUtil.generateCallbackUrl("/rest/dm/receiver/"+jobDetail.getJobId());
            // 设置回调地址
            oracleCmdBuilder.setResultCallBackUrl(resultReceiver);
            List<String> allUsedBackupFiles=new ArrayList<>();
            allUsedBackupFiles.add(backupJobDetail.getServerPath());
            oracleCmdBuilder.dbRestore(backupJobDetail.getClientPath(),allUsedBackupFiles);
            // 将备份命令转化为json字符串
            String cmd=oracleCmdBuilder.buildToJSONString();
            // 保存job发出的cmd记录
            jobDetail.setJobCommand(cmd);
            jobDetail.setDataType(DataTypeEnum.DATABASE.getValue());
            // 将命令提交到代理端执行
            String postToClient = cn.hutool.http.HttpUtil.post(client.getNodeClientAgentUrl(),cmd);
            // 获取代理对命令的响应
            PortalResult portalResult = JSON.parseObject(postToClient,PortalResult.class);
            if(!portalResult.getStatus().equals(StatusConst.SUCCESS))
            {
                jobDetail.setJobResult("请求代理客户端失败:"+postToClient);
                jobDetail.setJobStatus(StatusConst.ERROR);
            }
        } catch (Exception e) {
            jobDetail.setJobResult(e.getMessage());
            jobDetail.setJobStatus(StatusConst.ERROR);
            e.printStackTrace();
        }
        // 将job记录存入表中
        int count = dbMysqlJobDetailService.insert(jobDetail);
        if(count>0) {
            return PortalResult.ok("恢复任务执行中，请稍后查看执行结果！");
        } else {
            return PortalResult.error("恢复记录到作业表中时失败");
        }
    }

    @RequestMapping("/receiver/{jobId}")
    public PortalResult receiver(@PathVariable("jobId") Long jobId, @RequestBody ClientCmdExecResult result)
    {
        if(jobId!=null && result!=null)
        {
            JobDetail jobDetail=jobDetailService.getById(jobId);
            if(jobDetail==null)
            {
                return PortalResult.error(jobId+" 不存在！");
            }
            jobDetail.setJobResult(JSON.toJSONString(result.getExecCmdResult()));
            jobDetail.setJobEndTime(TimeUtil.dateMaker());
            if(!result.isStatus())
            {
                LogUtil.logger.error(JSON.toJSONString(result.getErrorCmdList()));
            }
            String serverFilesPath = jobDetail.getServerPath();
            boolean transOK=true;
            if(serverFilesPath!=null)
            {
                for (String file:serverFilesPath.split(",")) {
                    transOK=cn.hutool.core.io.file.PathUtil.exists(Paths.get(file),true);
                    if(!transOK)
                    {
                        break;
                    }
                }
            }
            if(transOK)
            {
                jobDetail.setJobStatus(StatusConst.SUCCESS);
            }
            else
            {
                jobDetail.setJobStatus(StatusConst.ERROR);
            }
            Integer update= jobDetailService.updateByPrimaryKeySelective(jobDetail);
            return PortalResult.ok("成功更新"+update+"条数据记录！");
        }
        return PortalResult.error("结果上报参数不完整！");
    }
}


